import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import warnings
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import geopandas as gpd 
from urllib.request import urlopen
from numpy import mean
import folium
warnings.filterwarnings('ignore')

Precio del combustible en Colombia durante el 2023#

data1 = pd.read_csv("precios.csv")
data2 = pd.read_csv("precios (1).csv")
data3 = pd.read_csv("precios (2).csv")
data4 = pd.read_csv("precios (3).csv")

data = pd.concat([data1, data2, data3, data4], ignore_index=True)

display(data.head(10).style.set_caption("Base de datos: Precio del combustible en Colombia durante el 2023"))
Base de datos: Precio del combustible en Colombia durante el 2023
  BANDERA NOMBRE COMERCIAL PRODUCTO FECHA REGISTRO DEPARTAMENTO MUNICIPIO VALOR PRECIO
0 TERPEL ESTACION DE SERVICIO SERVICENTRO LA PEDRERA DIESEL 01-Jan-2023 AMAZONAS LA PEDRERA 15000.000000
1 TERPEL ESTACION DE SERVICIO SERVICENTRO LA PEDRERA GASOLINA MOTOR 01-Jan-2023 AMAZONAS LA PEDRERA 15500.000000
2 TERPEL BALSA EL CONDOR GASOLINA MOTOR 01-Jan-2023 AMAZONAS LETICIA 11380.000000
3 TERPEL BALSA EL CONDOR DIESEL 01-Jan-2023 AMAZONAS LETICIA 10840.000000
4 TERPEL ESTACION DE SERVICIO DISTRIBUIDORA LOS COMUNEROS GASOLINA MOTOR 01-Jan-2023 AMAZONAS LETICIA 11380.000000
5 TERPEL ESTACION DE SERVICIO DISTRIBUIDORA LOS COMUNEROS GASOLINA MOTOR 01-Jan-2023 AMAZONAS LETICIA 11380.000000
6 TERPEL ESTACION DE SERVICIO DISTRIBUIDORA LOS COMUNEROS DIESEL 01-Jan-2023 AMAZONAS LETICIA 10671.000000
7 TEXACO EDS COMDECOM ABRIAQUI GASOLINA MOTOR 01-Jan-2023 ANTIOQUIA ABRIAQUÍ 11870.000000
8 TEXACO EDS COMDECOM ABRIAQUI DIESEL 01-Jan-2023 ANTIOQUIA ABRIAQUÍ 10910.000000
9 TEXACO ESTACIÓN DE SERVICIO Y MALL SANTA LUCIA S.A.S. DIESEL 01-Jan-2023 ANTIOQUIA AMAGÁ 9610.000000
print(data.shape)
(268001, 7)

La base de datos ‘data’ contiene 268,001 observaciones distribuidas en 7 variables. A continuación, se presentan los nombres de las variables:

print(data.columns)
Index(['BANDERA', 'NOMBRE COMERCIAL', 'PRODUCTO', 'FECHA REGISTRO',
       'DEPARTAMENTO', 'MUNICIPIO', 'VALOR PRECIO'],
      dtype='object')

Análisis de Variables#

Variable Categórica#

Tabla de frecuencia variable ‘BANDERA’

conteo_banderas = data['BANDERA'].value_counts().reset_index()
conteo_banderas.columns = ['Bandera', 'Frecuencia']

print(conteo_banderas)
                Bandera  Frecuencia
0                TERPEL       94823
1                PRIMAX       36112
2                BIOMAX       32225
3                TEXACO       27092
4             PETROMIL        17249
5          COOMULPINORT        8918
6           AYATAWACOOP        8078
7                ZEUSS         7488
8             PETROBRAS        4871
9           DISCOWACOOP        3929
10                 ECOS        3613
11                 ESSO        3502
12            PETRDECOL        3495
13           PETRODECOL        3337
14                 PUMA        3059
15               DISCOM        2917
16               OCTANO        2221
17             PLUS MAS        1806
18                P Y B        1687
19                BRIO          719
20  ZAPATA Y VELASQUEZ          408
21                 SAVE         285
22              PROXXON         167

Tabla de frecuencia variable ‘DEPARTAMENTO’

conteo_departamentos = data['DEPARTAMENTO'].value_counts().reset_index()
conteo_departamentos.columns = ['Departamento', 'Frecuencia']
print(conteo_departamentos)
                                         Departamento  Frecuencia
0                                              NARIÑO       31054
1                                           ANTIOQUIA       25009
2                                  NORTE DE SANTANDER       21752
3                                     VALLE DEL CAUCA       18754
4                                        CUNDINAMARCA       16631
5                                         BOGOTA D.C.       16031
6                                               CESAR       15703
7                                          LA GUAJIRA       13694
8                                           SANTANDER       10247
9                                           ATLANTICO        8595
10                                             TOLIMA        8014
11                                             BOYACA        7769
12                                            CORDOBA        7440
13                                            BOLIVAR        7027
14                                           PUTUMAYO        6610
15                                              HUILA        6355
16                                               META        6250
17                                              CAUCA        5617
18                                          RISARALDA        5435
19                                          MAGDALENA        5339
20                                             CALDAS        4517
21                                              SUCRE        4358
22                                           CASANARE        2744
23                                              CHOCO        2640
24                                            QUINDIO        2555
25                                            CAQUETA        2390
26                                             ARAUCA        2312
27                                           GUAVIARE        1043
28                                            VICHADA         922
29                                           AMAZONAS         513
30  ARCHIPIELAGO DE SAN ANDRES, SANTA CATALINA Y P...         267
31                                            GUAINIA         261
32                                             VAUPES         153

Tabla de frecuencia variable ‘PRODUCTO’ y visualización de la distribución.

print(data['PRODUCTO'].value_counts().reset_index().rename(columns={'index': 'Producto', 'PRODUCTO': 'Frecuencia'}))

plt.figure(figsize=(10, 6))
sns.countplot(data=data, x='PRODUCTO', palette=['#0077b6', '#00b4d8', '#023e8a'])
plt.title('Distribución de combustible por producto')
plt.xlabel('PRODUCTO')
plt.ylabel('Frecuencia')
plt.xticks(rotation=45)
plt.show()
       Frecuencia   count
0  GASOLINA MOTOR  127338
1          DIESEL  108263
2           EXTRA   32400
_images/4fdeab014fa88d14e3a2d6bedc282611e523a2e0f27882d1a87811c16e24defa.png

Se nota que el combustible tipo Extra tiene una distribución considerablemente menor en comparación con la Gasolina Motor, que fue el combustible más vendido en Colombia durante el año 2023, con un total de 127.338 registros.

Variable Númerica#

print(data['VALOR PRECIO'].describe())

plt.figure(figsize=(10, 6))
plt.hist(data['VALOR PRECIO'].dropna(), bins=50, color='lightblue')
plt.title('Valor del combustible')
plt.xlabel('VALOR PRECIO')
plt.ylabel('Frecuencia')
plt.show()
count    2.680010e+05
mean     1.202214e+04
std      2.870676e+04
min      0.000000e+00
25%      9.350000e+03
50%      1.087000e+04
75%      1.384700e+04
max      1.475015e+07
Name: VALOR PRECIO, dtype: float64
_images/7219c7add91ef6d7c165383e7c73d0aa50d80025e6ac22497d190cd08de72611.png

Identificar datos faltantes#

## Identificar y manejar NA
print(data.isna().sum())
BANDERA             0
NOMBRE COMERCIAL    0
PRODUCTO            0
FECHA REGISTRO      0
DEPARTAMENTO        0
MUNICIPIO           0
VALOR PRECIO        0
dtype: int64

Detección de valores atípicos#

En el histograma de la variable numérica ‘VALOR PRECIO’ se observó una fuerte asimetría hacia la izquierda, indicando que la mayoría de los datos se encuentran concentrados en valores bajos. Además, se identificó un valor máximo significativamente mayor que el resto de los datos, lo que sugiere la presencia de valores atípicos o una cola larga en la distribución.

## Reemplazar valores atípicos
atipico = data['VALOR PRECIO'].quantile(0.98)
data.loc[data['VALOR PRECIO'] > atipico, 'VALOR PRECIO'] = pd.NA

median_value = data['VALOR PRECIO'].median()
data['VALOR PRECIO'].fillna(median_value, inplace=True)

plt.figure(figsize=(10, 6))
plt.boxplot(data['VALOR PRECIO'], patch_artist=True, boxprops=dict(facecolor='#6ab5b0'))
plt.title('Precio del combustible')
plt.ylabel('VALOR PRECIO')
plt.show()

print(data['VALOR PRECIO'].describe())
_images/bc7d92f382366a4a385ba4f1b307a3b88e29e5e52d3153ca286682825d68f7e2.png
count    268001.000000
mean      11755.836161
std        3257.278929
min           0.000000
25%        9350.000000
50%       10760.000000
75%       13610.000000
max       20282.000000
Name: VALOR PRECIO, dtype: float64

Para manejar los valores atípicos en la variable numérica, primero identificamos aquellos valores que se encuentran significativamente por encima del rango típico de la distribución, utilizando el percentil 98 como umbral. Los valores superiores a este umbral fueron reemplazados por NA para mitigar el impacto de los valores atípicos en el análisis. Posteriormente, los valores faltantes (NA) fueron imputados con la mediana de los datos restantes, garantizando así una base de datos más uniforme para el análisis.

print(data['VALOR PRECIO'].describe())
plt.figure(figsize=(10, 6))
plt.hist(data['VALOR PRECIO'].dropna(), bins=50, color='lightblue')
plt.title('Valor del combustible')
plt.xlabel('VALOR PRECIO')
plt.ylabel('Frecuencia')
plt.show()
count    268001.000000
mean      11755.836161
std        3257.278929
min           0.000000
25%        9350.000000
50%       10760.000000
75%       13610.000000
max       20282.000000
Name: VALOR PRECIO, dtype: float64
_images/a53f27049e64cc6238e7e78c94d8db3728a909f5573c39e4fe094baffa9f5263.png

Mapa de Colombia#

Mapa fijo#

Creamos una imagen representativa del mapa de colombia usando un archivo Shapefile

mapa = gpd.read_file("C:\\Users\\KELLY\\Documents\\MGN2023_DPTO_POLITICO (1)")


mapa['dpto_cnmbr'] = mapa['dpto_cnmbr'].replace({
    "NARI?O" : "NARIÑO","BOGOTÁ, D.C.":"BOGOTA D.C.", "BOLÍVAR" :"BOLIVAR","BOYACÁ":"BOYACA", "ATLÁNTICO":"ATLANTICO","CAQUETÁ": "CAQUETA", "CHOCÓ":"CHOCO","GUAINÍA":"GUAINIA","CÓRDOBA":"CORDOBA", "VAUPÉS":"VAUPES"
})

data['DEPARTAMENTO'] = data['DEPARTAMENTO'].replace({
    "ARCHIPIELAGO DE SAN ANDRES, SANTA CATALINA Y PROVIDENCIA": "ARCHIPIELAGO DE SAN ANDRES"
})

precios = data.groupby('DEPARTAMENTO')['VALOR PRECIO'].mean().reset_index()
precios.columns = ['DEPARTAMENTO', 'PROMEDIO']
mapa = mapa.rename(columns={'dpto_cnmbr': 'DEPARTAMENTO'})
mapa = mapa.merge(precios, on='DEPARTAMENTO')

norm = mcolors.Normalize(vmin=mapa['PROMEDIO'].min(), vmax=mapa['PROMEDIO'].max())
cmap = plt.get_cmap('plasma_r')


fig, ax = plt.subplots(1, 1, figsize=(14, 10))


mapa.plot(column='PROMEDIO', ax=ax, legend=True, cmap=cmap, norm=norm, edgecolor='black',
         legend_kwds={'label': "Precio Promedio",
                      'orientation': "vertical"})


for x, y, label in zip(mapa.geometry.centroid.x, mapa.geometry.centroid.y, mapa['DEPARTAMENTO']):
    ax.annotate(label, xy=(x, y), xytext=(-10, -5), textcoords='offset points', fontsize=7, color='Black')


plt.title('Precio Promedio por Departamento en Colombia')

plt.show()
_images/2d1ab50ba649896cd50f0b3bab8b9b7c6901ba799322217a9779aeea1cce1d73.png

Mapa interactivo#

Para hacer el mapa interactivo, se usó la biblioteca folium en lugar de matplotlib. folium permite crear mapas interactivos en los que puedes hacer zoom, mover el mapa, y agregar elementos interactivos como pop-ups.

m = folium.Map(location=[4.5709, -74.2973], zoom_start=6)

folium.Choropleth(
    geo_data=mapa,
    name='choropleth',
    data=mapa,
    columns=['DEPARTAMENTO', 'PROMEDIO'],
    key_on='feature.properties.DEPARTAMENTO',
    fill_color='plasma_r',
    fill_opacity=0.5,
    line_opacity=0.7,
    legend_name='Precio Promedio',
    highlight=True
).add_to(m)

for _, row in mapa.iterrows():
    folium.Popup(f"{row['DEPARTAMENTO']}: {row['PROMEDIO']:.2f}").add_to(
        folium.GeoJson(row['geometry'], name=row['DEPARTAMENTO'])
    )

folium.LayerControl().add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook